home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 8 / The Arsenal Files Collection #8 (Arsenal Computer) (1996).ISO / prg_gen / euphor14.zip / SEARCH.EX < prev    next >
Text File  |  1996-05-31  |  11KB  |  445 lines

  1. -- This program searches for a string in files of the current directory 
  2. -- and subdirectories.
  3. -- usage:  
  4. --      search [string] 
  5. --
  6. -- If you don't supply a string on the command line you will be prompted 
  7. -- for it. The string may contain * and ? wildcard characters and so may 
  8. -- the list of file specifications. Lines containing the string are 
  9. -- displayed on the screen, and also recorded in C:\SEARCH.OUT. 
  10. -- Some statistics are printed at the end.
  11. -- Example:
  12. --
  13. --   C:\> search
  14. --   string: p?oc*re
  15. --   match case? (n)
  16. --   file-spec (*.*): *.e *.ex
  17. --   scan subdirectories? (y)
  18. --
  19. -- Note: if you just hit Enter instead of supplying a string to search for,
  20. -- the program will simply print any file names that match your file-spec.
  21.  
  22. -------- some user-modifiable parameters: 
  23.  
  24. sequence log_name, log_path
  25. log_name = "search.out"
  26. log_path = "c:\\" & log_name  -- place to store results
  27.  
  28. -- when you search "*.*" the following files 
  29. -- will actually be skipped (to save time):
  30. sequence skip_list 
  31. skip_list = {
  32.     "*.EXE", "*.ZIP", "*.BMP", "*.GIF", "*.OBJ",
  33.     "*.DLL", "*.OBJ", "*.SWP", "*.PAR", "*.JPG" 
  34. }
  35.  
  36. -------- end of user-modifiable parameters 
  37.  
  38. without type_check
  39.  
  40. include file.e
  41. include wildcard.e
  42. include sort.e
  43. include graphics.e
  44.  
  45. constant KEYB = 0, SCREEN = 1, ERR = 2
  46.  
  47. constant TRUE = 1, FALSE = 0
  48. constant EOF = -1
  49.  
  50. type boolean(integer x)
  51.     return x = 0 or x = 1
  52. end type
  53.  
  54. sequence pos, cmd, string, orig_string, file_spec
  55.  
  56. boolean match_case, scan_subdirs, wild_string
  57.  
  58. integer line_count
  59.  
  60. integer scanned, skipped, no_open, total_found
  61. scanned = 0
  62. skipped = 0
  63. no_open = 0
  64. total_found = 0
  65.  
  66. atom start_time
  67. integer log_file
  68.  
  69. function alphabetic(object s)
  70. -- does s contain alphabetic characters?
  71.     return find(TRUE, (s >= 'A' and s <= 'Z') or
  72.               (s >= 'a' and s <= 'z')) 
  73. end function
  74.  
  75. constant LINE_WIDTH = 79
  76.  
  77. function clean(sequence line)
  78. -- replace any funny control characters 
  79. -- and put in \n's to help break up long lines
  80.     sequence new_line
  81.     integer c, col
  82.     
  83.     new_line = ""
  84.     col = 1
  85.     for i = 1 to length(line) do
  86.     if col > LINE_WIDTH then
  87.         new_line = append(new_line, '\n')
  88.         col = 1
  89.     end if
  90.     c = line[i]
  91.     col = col + 1
  92.     if c < 14 then
  93.         if c = '\t' or c = '\r' then
  94.         c = ' '
  95.         elsif c = '\n' then
  96.         col = 1
  97.         else    
  98.         c = '.'
  99.         end if
  100.     end if
  101.     new_line = append(new_line, c)
  102.     end for
  103.     if length(line) > 1.5 * LINE_WIDTH then
  104.     new_line = new_line & '\n'
  105.     end if
  106.     return new_line
  107. end function
  108.  
  109. procedure both_puts(object text)
  110.     puts(SCREEN, text)
  111.     puts(log_file, text)
  112. end procedure
  113.  
  114. procedure both_printf(sequence format, object values)
  115.     printf(SCREEN, format, values)
  116.     printf(log_file, format, values)
  117. end procedure
  118.  
  119. function plural(integer n)
  120. -- Yes, this is a bit obsessive...
  121.     if n = 1 then
  122.     return ""
  123.     else
  124.     return "s"
  125.     end if
  126. end function
  127.  
  128. procedure list_file_spec()
  129.     for i = 1 to length(file_spec) do
  130.     both_puts(file_spec[i])
  131.     if i != length(file_spec) then
  132.         both_puts(" ")
  133.     end if
  134.     end for
  135. end procedure
  136.  
  137. procedure final_stats()
  138. -- show final statistics    
  139.  
  140.     puts(SCREEN, repeat(' ', 80))
  141.     if length(string) = 0 then
  142.     both_printf("%d file name" & plural(total_found) & " matched (", 
  143.              total_found)
  144.     list_file_spec()
  145.     both_puts(")\n")
  146.     both_printf("%d names did not match\n", skipped)
  147.     else
  148.     both_printf("\n%5d file" & plural(scanned) & " scanned (", scanned)
  149.     list_file_spec()
  150.     both_printf(")\n%5d file" & plural(skipped) & " skipped\n", skipped)
  151.     both_printf("%5d file" & plural(total_found) & 
  152.             " contained \"%s\" ", {total_found, orig_string})
  153.     if alphabetic(orig_string) then
  154.         if match_case then
  155.         both_puts("(case must match)")
  156.         else
  157.         both_puts("(any case)")
  158.         end if
  159.     end if
  160.     both_puts('\n')
  161.     if no_open then
  162.         both_printf("couldn't open %d file" & plural(no_open) & '\n', 
  163.              no_open)
  164.     end if
  165.     end if
  166.     printf(SCREEN, "search time: %.1f seconds\n", time()-start_time)
  167.     if total_found then
  168.     puts(SCREEN, "\nSee " & log_path & '\n')
  169.     end if
  170.     close(log_file)
  171. end procedure
  172.  
  173. constant MAX_LINE = 500 
  174.  
  175. -- space for largest line
  176. sequence buff
  177. buff = repeat(0, MAX_LINE)
  178.  
  179. function safe_gets(integer fn)
  180. -- Return the next line of text.
  181. -- Lines are split at MAX_LINE to prevent
  182. -- "out of memory" problems on humongous lines
  183. -- and to reduce the amount of extraneous output.
  184.     integer c
  185.     
  186.     for b = 1 to MAX_LINE-1 do
  187.     c = getc(fn)
  188.     if c <= '\n' then
  189.         if c = '\n' then
  190.         buff[b] = c
  191.         return buff[1..b]
  192.         elsif c = EOF then
  193.         if b = 1 then
  194.             return EOF
  195.         else
  196.             exit
  197.         end if
  198.         end if
  199.     end if
  200.     buff[b] = c
  201.     end for
  202.     buff[MAX_LINE] = '\n'
  203.     return buff[1..MAX_LINE]
  204. end function
  205.  
  206. constant SAFE_FILE_SIZE = 100000
  207.  
  208. function scan(sequence file_name, integer file_size, sequence string)
  209. -- print all lines in current file containing the string
  210.     object line
  211.     sequence match_line
  212.     integer fileNum
  213.     boolean found, found_in_file
  214.     
  215.     wrap(FALSE)
  216.     puts(SCREEN, file_name & ':' & repeat(' ', 80) & '\r')
  217.     wrap(TRUE)
  218.     fileNum = open(file_name, "rb")   
  219.     if fileNum = -1 then
  220.     no_open = no_open + 1
  221.     both_puts(file_name & ": Couldn't open. Probably locked.\t\t\t\n")
  222.     return 0
  223.     end if
  224.     found_in_file = FALSE
  225.     while TRUE do
  226.     if file_size > SAFE_FILE_SIZE then
  227.         line = safe_gets(fileNum)
  228.     else
  229.         line = gets(fileNum)    
  230.     end if
  231.     if atom(line) then
  232.         exit -- end of file
  233.     else
  234.         if match_case then
  235.         match_line = line
  236.         else
  237.         match_line = lower(line)
  238.         end if
  239.         if wild_string then
  240.         found = wildcard_match(string, match_line) 
  241.         else        
  242.         found = match(string, match_line) 
  243.         end if
  244.         if found then
  245.         both_puts(clean(file_name & ": " & line))
  246.         found_in_file = TRUE
  247.         end if
  248.     end if
  249.     end while
  250.     
  251.     scanned = scanned + 1
  252.     close(fileNum)
  253.     return found_in_file
  254. end function
  255.  
  256. procedure look_at(sequence path_name, sequence entry)
  257. -- see if a file name qualifies for searching
  258.     boolean matched_one
  259.     sequence file_name
  260.     
  261.     file_name = entry[D_NAME]
  262.     if compare(file_name, log_name) = 0 then
  263.     return -- avoid circularity
  264.     end if
  265.     if compare(file_spec[1], "*.*") = 0 then
  266.     -- check skip list
  267.     for i = 1 to length(skip_list) do
  268.         if wildcard_file(skip_list[i], file_name) then
  269.         skipped = skipped + 1
  270.         return
  271.         end if
  272.     end for
  273.     else
  274.     -- go through list of file specs
  275.     matched_one = FALSE
  276.     for i = 1 to length(file_spec) do
  277.         if wildcard_file(file_spec[i], file_name) then
  278.         matched_one = TRUE
  279.         exit
  280.         end if
  281.     end for
  282.     if not matched_one then
  283.         skipped = skipped + 1
  284.         return
  285.     end if
  286.     end if
  287.     path_name = path_name & '\\'
  288.     if compare(path_name[1..2], ".\\") = 0 then
  289.     path_name = path_name[3..length(path_name)]
  290.     end if
  291.     path_name = path_name & file_name
  292.     if length(string) = 0 then
  293.     -- just looking for file names
  294.     both_printf("%4d-%02d-%02d %2d:%02d", entry[D_YEAR..D_MINUTE])
  295.     both_printf(" %7d  %s\n", {entry[D_SIZE], path_name})
  296.     total_found = total_found + 1
  297.     else
  298.     total_found = total_found + scan(path_name, entry[D_SIZE], string)
  299.     end if
  300. end procedure
  301.  
  302. procedure walk_dir(sequence path_name)
  303. -- walk through a directory and its subdirectories 
  304. -- in alphabetical order, "looking" at each file
  305.     object d
  306.     
  307.     d = dir(path_name)
  308.     while find(path_name[length(path_name)], " \\") do
  309.     path_name = path_name[1..length(path_name)-1]
  310.     end while
  311.     if atom(d) then
  312.     puts(ERR, "\nCouldn't access " & path_name & '\n')
  313.     return
  314.     end if
  315.     d = sort(d) -- sort-by-name (first field of d)
  316.     for i = 1 to length(d) do
  317.     if find('d', d[i][D_ATTRIBUTES]) then
  318.         if not find(d[i][D_NAME], {".", ".."}) then
  319.         if scan_subdirs then
  320.             walk_dir(path_name & '\\' & d[i][D_NAME])
  321.         end if
  322.         end if
  323.     else
  324.         look_at(path_name, d[i])
  325.     end if
  326.     if get_key() = 'q' then
  327.         final_stats()
  328.         abort(1)
  329.     end if
  330.     end for
  331. end procedure
  332.  
  333. function blank_delim(sequence s)
  334. -- break up a blank-delimited string
  335.     sequence list, segment
  336.     integer i
  337.     list = {}
  338.     i = 1
  339.     while i < length(s) do
  340.     while find(s[i], " \t") do
  341.         i = i + 1
  342.     end while
  343.     if s[i] = '\n' then
  344.         exit
  345.     end if
  346.     segment = ""
  347.     while not find(s[i], " \t\n") do
  348.         segment = segment & s[i]
  349.         i = i + 1
  350.     end while
  351.     list = append(list, segment)
  352.     end while
  353.     return list
  354. end function
  355.  
  356. procedure get_file_spec()
  357. -- read in a list of file specifications from user
  358. -- result is stored in file_spec sequence of strings
  359.     sequence spec
  360.     
  361.     puts(SCREEN, "file-spec (*.*): ")
  362.     spec = gets(KEYB)
  363.     puts(SCREEN, '\n')
  364.     file_spec = blank_delim(spec)
  365.     if length(file_spec) = 0 then
  366.     file_spec = {"*.*"}
  367.     end if
  368. end procedure
  369.  
  370. log_name = upper(log_name)
  371.  
  372. cmd = command_line()   -- ex search.ex [string]
  373.  
  374. if length(cmd) >= 3 then
  375.     orig_string = cmd[3]
  376. else
  377.     puts(SCREEN, "string:")
  378.     orig_string = gets(KEYB)
  379.     orig_string = orig_string[1..length(orig_string)-1] -- remove \n
  380.     puts(SCREEN, '\n')
  381. end if
  382.  
  383. if alphabetic(orig_string) then
  384.     puts(SCREEN, "match case? (n)")
  385.     pos = get_position()
  386.     position(pos[1], pos[2] - 2)
  387.     match_case = find('y', gets(KEYB))
  388.     puts(SCREEN, '\n')
  389. else
  390.     match_case = TRUE   
  391. end if
  392.  
  393. string = orig_string
  394. if not match_case then
  395.     string = lower(string)
  396. end if
  397.  
  398. wild_string = find('?', string) or find('*', string) 
  399. if wild_string then
  400.     string = '*' & string & '*' -- to match whole line
  401. end if
  402.  
  403. get_file_spec()
  404.  
  405. -- avoid asking about subdirectories 
  406. -- when there aren't any...
  407. object d
  408. d = dir(current_dir())
  409. if atom(d) then
  410.     puts(SCREEN, "network drive not available\n")
  411.     abort(1)
  412. end if
  413. for i = 1 to length(d) do
  414.     if find('d', d[i][D_ATTRIBUTES]) then
  415.     if not find(d[i][D_NAME], {".", ".."}) then
  416.         puts(SCREEN, "scan subdirectories? (y)")
  417.         pos = get_position()
  418.         position(pos[1], pos[2] - 2)
  419.         scan_subdirs = not match("n", gets(KEYB))
  420.         exit
  421.     end if          
  422.     end if
  423. end for
  424.  
  425. puts(SCREEN, "\npress q to quit\n\n")
  426.  
  427. log_file = open(log_path, "w")
  428. if log_file = -1 then
  429.     puts(ERR, "Couldn't open " & log_path & '\n')
  430.     abort(1)
  431. end if
  432.  
  433. start_time = time()
  434. if sequence(dir(".")) then
  435.     puts(log_file, "Searching " & current_dir() & "\n\n")
  436.     walk_dir(".")
  437. else
  438.     walk_dir(current_dir())
  439. end if
  440.  
  441. final_stats()
  442.  
  443. without warning
  444.  
  445.